
package com.fiveflavors.suittar;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

import twitter4j.DirectMessage;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.User;
import twitter4j.UserWithStatus;

import com.fiveflavors.suittar.growl.GrowlHelper;
import com.fiveflavors.suittar.gui.BrowserLauncher;
import com.fiveflavors.suittar.gui.SuittarFrame;
import com.fiveflavors.suittar.gui.SuittarLoginDialog;
import com.fiveflavors.suittar.gui.SuittarTabbedPane;
import com.fiveflavors.suittar.gui.inputpanel.SuittarInputPanel;
import com.fiveflavors.suittar.gui.mainpanel.SuittarMainPane;
import com.fiveflavors.suittar.gui.mainpanel.view.SuittarTimeLineViewBean;
import com.fiveflavors.suittar.gui.mainpanel.view.SuittarTimeLineViewManager;
import com.fiveflavors.suittar.property.SuittarProperty;

/**
 * Copyright (c) 2007,2008, Masaaki Gomi.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Masaaki Gomi nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY Masaaki Gomi ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Masaaki Gomi BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * @author marr
 * @author withgod
 */
public class Suittar {

	private static final String CLIENT_NAME = "suittar";
	private static final String CLIENT_VERSION = "2.0 (kashikiriyama)";
	private static final String CLIENT_URL = "http://www.fiveflavors.com/suittar/jws/suittar.xml";

	private Twitter twitter = null;
	
    private int latestId = -1;

    private SuittarFrame frame = null;
    
    private Runnable refreshThread = null;
	private int timeLineRefreshCount = 0;
	private int refreshInterval = 0;
	
	private ScheduledExecutorService exeService = Executors.newScheduledThreadPool(1);
	private ScheduledFuture<?> future = null;

	private UserWithStatus myUser = null;
	private List<User> myFriendList = null;
	private List<String> myFriendScreenNameList = null;

	private UserWithStatus selectedUser = null;
	private List<User> selectedUserFriendList = null;
	
	private boolean	tabChangeEventOff = false;
	
	private SuittarProperty props = null;

	/** GrowlSupport */
	private boolean isGrowlSupport = false;
	private boolean showGrowl = false;

	private Suittar() {

		try {
			props = new SuittarProperty();
			props.loadProperties();
			
			//GrowlSupport
			isGrowlSupport = GrowlHelper.checkGrowlSupport();
			
			frame = new SuittarFrame(this);
			frame.setVisible(true);

			myUser = signIn();
			selectedUser = myUser;
			frame.getStatusBar().setSelectedInterval(refreshInterval);

			getMyFollowingList();

			refreshThread = new AutoTimeLineUpdater();
			future = exeService.scheduleAtFixedRate(refreshThread, 0, 1000,TimeUnit.MILLISECONDS);

			executeSuittarCommand();

			frame.addAllEventListener(this);

		}
		catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	private UserWithStatus signIn() throws TwitterException {

		SuittarLoginDialog dialog = new SuittarLoginDialog(frame, props);
		boolean wasLogin = false;

		dialog.setProperties();

		while (!wasLogin) {

			dialog.setVisible(true);

			if (dialog.getResult() == SuittarLoginDialog.RESULT_CANCEL) {
				System.exit(0);
			}
			
			try {
				if (dialog.isSaveProperty()){
					//SuittarProperty.saveProperties(dialog.getProperties());
					dialog.updateProperties();
				}
			}
			catch (IOException e) {
				String[] message = {
						"IOException occurred when save properties.",
						"Continue ??"
				};
				int value = JOptionPane.showConfirmDialog(frame , message ,"SignIn Error" , JOptionPane.OK_CANCEL_OPTION);
				if (value == JOptionPane.CANCEL_OPTION) {
					System.exit(0);
				}
			}

			String userName = dialog.getUserName();
			String password = dialog.getPassword();
			String baseUrl = dialog.getBaseUrl();

			if (baseUrl.length() == 0) {
				baseUrl = SuittarProperty.TWITTER_DEFAULT_BASE_URL;
			}
			
			if (userName.length() == 0 || password.length() == 0) {
				continue;
			}
					
			// Proxy使用可否
			if (dialog.isUseProxy()) {
				System.setProperty("http.proxyHost", dialog.getProxyHost());
				System.setProperty("http.proxyPort", dialog.getProxyPort());			
			}

			//Growl
			if (isGrowlSupport) {
				isGrowlSupport = dialog.isUseGrowl();
			}
			
			frame.getStatusBar().setRefreshing(true);
			
			twitter = new Twitter(userName,password,baseUrl);
			
			twitter.setRequestHeader("X-Twitter-Client", CLIENT_NAME);
			twitter.setRequestHeader("X-Twitter-Client-Version", CLIENT_VERSION);
			twitter.setRequestHeader("X-Twitter-Client-URL", CLIENT_URL);
			twitter.setSource(CLIENT_NAME);
			
			try {
				
				myUser = twitter.getUserDetail(userName);

				refreshInterval = dialog.getRefreshInterval();
				int defaultCommand = dialog.getDefaultView();
				SuittarCommand.initialize(defaultCommand, myUser.getScreenName(), 1);
				
				int index = 0;
				int subIndex = 0;
				if (defaultCommand == SuittarFrame.TAB_MAIN_PUBLIC) {
					index = SuittarFrame.TAB_MAIN_PUBLIC;
				}
				else {
					index = SuittarFrame.TAB_MAIN_MYUSER;
					subIndex = defaultCommand - 1;
				}
				frame.setMainPaneFont(dialog.getMainPaneFont());
				
				frame.setSelectedTabIndex(index,subIndex);

				if (dialog.isEnterToUpdate()) {
					frame.getInputPane().addEnterActionListener(this);					
				}
				
				wasLogin = true;

			}
			catch (TwitterException e) {
				/*
				 * -1  - ???
				 * 400 - Bad Request - (rate limit over)
				 * 401 - Unauthorized
				 * 404 - Not Found
				 */
				String msg = e.getMessage();
				String statusCode = "[status code]"  + String.valueOf(e.getStatusCode());
				String[] message = {
						"Could not sign-in.",
						statusCode,
						msg,
						"Try again or Cancel ??"
				};
				int value = JOptionPane.showConfirmDialog(frame , message ,"Login Error" , JOptionPane.OK_CANCEL_OPTION);
				if (value == JOptionPane.CANCEL_OPTION) {
					System.exit(0);
				}
			}			
		}
		frame.getStatusBar().setRefreshing(false);

		
		return myUser;
	}
	
	private synchronized void getMyFollowingList() {

		frame.getStatusBar().setRefreshing(true);

		try {

			myFriendList = twitter.getFriends();
			
			myFriendScreenNameList = new ArrayList<String>();
			for (User user: myFriendList) {
				myFriendScreenNameList.add(user.getScreenName());
			}
			
			frame.getInputPane().getDirectMessagePanel().setFriendList(myFriendList);
			
			if (frame.getSelectedMainTabIndex() == SuittarFrame.TAB_MAIN_MYUSER && 
					frame.getSelectedOwnerTabIndex() == SuittarTabbedPane.TAB_OWNER_FOLLOWING) {
				SuittarMainPane followingPane = frame.getMainPane(SuittarFrame.TAB_MAIN_MYUSER, SuittarTabbedPane.TAB_OWNER_FOLLOWING);
				followingPane.showFollowing(myUser, myFriendList);
			}
			
		}
		catch (TwitterException e) {			
		}
		finally {
			frame.getStatusBar().setRefreshing(false);			
		}
		
	}
	
	private synchronized void setFollowing() {

		frame.getStatusBar().setRefreshing(true);
		
		try {
			
			//自動更新の場合、自ユーザ
			if (SuittarCommand.isExecFromTimer()) {
				selectedUser = myUser;
			}
			else {
				//コマンドと同一ユーザの場合、自ユーザ
				if (myUser.getScreenName().equals(SuittarCommand.getScreenName())) {
					selectedUser = myUser;					
				}
				//手動更新で、前回ユーザと異なる場合、ユーザ詳細を取得
				else if (!selectedUser.getScreenName().equals(SuittarCommand.getScreenName())) {
					selectedUser = twitter.getUserDetail(SuittarCommand.getScreenName());				
				}
			}

			selectedUserFriendList = twitter.getFriends(SuittarCommand.getScreenName());
			
			SuittarMainPane mainPane = null;
			if (selectedUser.getId() == myUser.getId()) {
				myFriendList = selectedUserFriendList;
				
				myFriendScreenNameList = new ArrayList<String>();
				for (User user: myFriendList) {
					myFriendScreenNameList.add(user.getScreenName());
				}
				frame.getInputPane().getDirectMessagePanel().setFriendList(myFriendList);
				mainPane = frame.getMainPane(SuittarFrame.TAB_MAIN_MYUSER, SuittarTabbedPane.TAB_OWNER_FOLLOWING);
			}
			else {
				int index = frame.findUserTab(selectedUser.getId());
				mainPane = frame.getMainPane(index,SuittarTabbedPane.TAB_OTHER_FOLLOWING);
			}
			mainPane.showFollowing(selectedUser, selectedUserFriendList);
		}
		catch (TwitterException e) {			
		}
		finally {
			frame.getStatusBar().setRefreshing(false);			
		}
		
	}

	private void setFollowers() throws TwitterException {
		List<User> followers = twitter.getFollowers();		
		SuittarMainPane mainPane = frame.getMainPane(SuittarFrame.TAB_MAIN_MYUSER, SuittarTabbedPane.TAB_OWNER_FOLLOWERS);
		mainPane.showFollowers(myUser,followers);
	}
	
	private void setPublicTimeLine() throws TwitterException {
		List<Status> statusList = null;
		if (latestId == -1) {
			statusList = twitter.getPublicTimeline();
		}
		else {
			statusList = twitter.getPublicTimeline(latestId);
		}

		SuittarTimeLineViewBean timeLineViewBean = new SuittarTimeLineViewBean(myUser);
		timeLineViewBean.setView(SuittarTimeLineViewManager.VIEWTYPE_PUBLIC);
		timeLineViewBean.setStatusList(statusList);
		timeLineViewBean.setLatestId(latestId);
		latestId = frame.getMainPane(SuittarFrame.TAB_MAIN_PUBLIC,SuittarFrame.TAB_MAIN_PUBLIC).showTimeLine(timeLineViewBean);

	}
	
	private void setFriendsTimeLine() throws TwitterException {

		//自動更新の場合、自ユーザ
		if (SuittarCommand.isExecFromTimer()) {
			selectedUser = myUser;
		}
		else {
			//コマンドと同一ユーザの場合、自ユーザ
			if (myUser.getScreenName().equals(SuittarCommand.getScreenName())) {
				selectedUser = myUser;					
			}
			//手動更新で、前回ユーザと異なる場合、ユーザ詳細を取得
			else if (!selectedUser.getScreenName().equals(SuittarCommand.getScreenName())) {
				selectedUser = twitter.getUserDetail(SuittarCommand.getScreenName());				
			}
		}
		
		List<Status> statusList = twitter.getFriendsTimelineByPage(SuittarCommand.getScreenName(), SuittarCommand.getPage());
		
		//GrowlSupport
		if (isGrowlSupport) {
			GrowlHelper.notifyTimeLine2Growl(statusList,showGrowl);
		}

		SuittarTimeLineViewBean timeLineViewBean = new SuittarTimeLineViewBean(myUser);
		timeLineViewBean.setView(SuittarTimeLineViewManager.VIEWTYPE_FRIENDS);
		timeLineViewBean.setStatusList(statusList);
		timeLineViewBean.setSelectedUser(selectedUser);
		timeLineViewBean.setPage(SuittarCommand.getPage());
		timeLineViewBean.setFriendList(selectedUserFriendList);
		timeLineViewBean.setLatestId(latestId);
		
		SuittarMainPane mainPane = null;
		if (selectedUser.getId() == myUser.getId()) {
			mainPane = frame.getMainPane(SuittarFrame.TAB_MAIN_MYUSER, SuittarTabbedPane.TAB_OWNER_FRIENDS);
		}
		else {
			int index = frame.findUserTab(selectedUser.getId());
			mainPane = frame.getMainPane(index,SuittarTabbedPane.TAB_OTHER_FRIENDS);
		}
		mainPane.showTimeLine(timeLineViewBean);
		
		//2回目以降に有効
		showGrowl = true;
	}
	
	private void setProfileTimeLine() throws TwitterException {
		
		//自動更新の場合、自ユーザ
		if (SuittarCommand.isExecFromTimer()) {
			selectedUser = myUser;
		}
		else {
			//コマンドと同一ユーザの場合、自ユーザ
			if (myUser.getScreenName().equals(SuittarCommand.getScreenName())) {
				selectedUser = myUser;					
			}
			//手動更新で、前回ユーザと異なる場合、ユーザ詳細を取得
			else if (!selectedUser.getScreenName().equals(SuittarCommand.getScreenName())) {
				selectedUser = twitter.getUserDetail(SuittarCommand.getScreenName());				
			}
		}

		List<Status> statusList = twitter.getUserTimeline(SuittarCommand.getScreenName());
		
		SuittarMainPane mainPane = null;
		int index = 0;
		int subIndex = 0;
		tabChangeEventOff = true;
		if (selectedUser.getId() == myUser.getId()) {
			selectedUserFriendList = myFriendList;
			index = SuittarFrame.TAB_MAIN_MYUSER;
			subIndex = SuittarTabbedPane.TAB_OWNER_PROFILE;
			mainPane = frame.getMainPane(SuittarFrame.TAB_MAIN_MYUSER,SuittarTabbedPane.TAB_OWNER_PROFILE);
		}
		else {
			selectedUserFriendList = twitter.getFriends(SuittarCommand.getScreenName());
			index = frame.findUserTab(selectedUser.getId());
			if (index == -1) {
				index = frame.addNewUserTab(selectedUser,this);
				mainPane = frame.getMainPane(index,SuittarTabbedPane.TAB_OTHER_PROFILE);				
			}
			else {
				mainPane = frame.getMainPane(index,SuittarTabbedPane.TAB_OTHER_PROFILE);				
			}
			subIndex = SuittarTabbedPane.TAB_OTHER_PROFILE;
		}
		frame.setSelectedTabIndex(index, subIndex);
		tabChangeEventOff = false;
		
		SuittarTimeLineViewBean timeLineViewBean = new SuittarTimeLineViewBean(myUser);
		timeLineViewBean.setView(SuittarTimeLineViewManager.VIEWTYPE_PROFILE);
		timeLineViewBean.setAuthUser(myUser.getScreenName().equals(SuittarCommand.getScreenName()));
		timeLineViewBean.setAlreadyFriend(myFriendScreenNameList.contains(SuittarCommand.getScreenName()));
		timeLineViewBean.setSelectedUser(selectedUser);
		timeLineViewBean.setStatusList(statusList);
		timeLineViewBean.setLatestId(latestId);
		mainPane.showTimeLine(timeLineViewBean);
		
	}
	
	 private void setRepliesTimeLine() throws TwitterException {
		List<Status> statusList = null;
		try {
			statusList = twitter.getRepliesByPage(SuittarCommand.getPage());			
		}
		catch (TwitterException e) {
			statusList = new ArrayList<Status>();
		}
		SuittarTimeLineViewBean timeLineViewBean = new SuittarTimeLineViewBean(myUser);
		timeLineViewBean.setPage(SuittarCommand.getPage());
		timeLineViewBean.setView(SuittarTimeLineViewManager.VIEWTYPE_REPLIES);

		timeLineViewBean.setSelectedUser(myUser);
		timeLineViewBean.setStatusList(statusList);
		
		SuittarMainPane mainPane = frame.getMainPane(SuittarFrame.TAB_MAIN_MYUSER, SuittarTabbedPane.TAB_OWNER_REPLIES);
		mainPane.showTimeLine(timeLineViewBean);
	}

	private void setDirectMessages() throws TwitterException {
			List<DirectMessage> sent = null;
			List<DirectMessage> receive = null;
			try {
				receive = twitter.getDirectMessages();			
				sent = twitter.getSentDirectMessages();			
				//receive = twitter.getDirectMessagesByPage(page);			
				//sent = twitter.getSentDirectMessages(page);			
			}
			catch (TwitterException e) {
				receive = new ArrayList<DirectMessage>();			
				sent = new ArrayList<DirectMessage>();		
			}
			SuittarTimeLineViewBean timeLineViewBean = new SuittarTimeLineViewBean(myUser);
			timeLineViewBean.setPage(SuittarCommand.getPage());
			frame.getInputPane().setMode(SuittarInputPanel.MODE_DIRECT_MESSAGE);
			
			SuittarMainPane mainPane = frame.getMainPane(SuittarFrame.TAB_MAIN_MYUSER, SuittarTabbedPane.TAB_OWNER_DIRECT_MESSAGES);
			mainPane.showDirectMessages(timeLineViewBean, sent, receive);
	}

	private synchronized void setTimeLine() {
		
		frame.getStatusBar().setRefreshing(true);
		frame.getStatusBar().setMessage("");
		
		if (SuittarCommand.isCommandChanged()) {
			latestId = -1;
		}

		try {
			
			switch(SuittarCommand.getCommand()) {
			
			case SuittarCommand.COMMAND_SHOW_PUBLIC:
				setPublicTimeLine();
				break;
			case SuittarCommand.COMMAND_SHOW_FRIENDS:
				if (SuittarCommand.isExecFromTimer()) {
					SuittarCommand.setPage(1);
				}
				setFriendsTimeLine();					
				break;			
			case SuittarCommand.COMMAND_SHOW_PROFILE:
				setProfileTimeLine();
				break;			
			case SuittarCommand.COMMAND_SHOW_REPLIES:
				if (SuittarCommand.isExecFromTimer()) {
					SuittarCommand.setPage(1);
				}
				setRepliesTimeLine();
				break;			
			case SuittarCommand.COMMAND_SHOW_FOLLOWERS:
				setFollowers();
				break;
			case SuittarCommand.COMMAND_SHOW_FOLLOWING:
				setFollowing();
				break;
			case SuittarCommand.COMMAND_SHOW_DIRECT_MESSAGE:
				if (SuittarCommand.isExecFromTimer()) {
					SuittarCommand.setPage(1);
				}
				setDirectMessages();
				break;
			default:
				throw new TwitterException("Ignore Command : " + SuittarCommand.getCommand());	
			}
		}
		catch (TwitterException e) {

			/*
			 * -1  - Out Of Service??
			 * 400 - Bad Request - (rate limit over)
			 * 401 - Unauthorized
			 * 404 - Not Found
			 * 
			 * 200 OK: everything went awesome.
			 * 304 Not Modified: there was no new data to return.
			 * 400 Bad Request: your request is invalid, and we'll return an error message that tells you why. This is the status code returned if you've exceeded the rate limit (see below). 
			 * 401 Not Authorized: either you need to provide authentication credentials, or the credentials provided aren't valid.
			 * 403 Forbidden: we understand your request, but are refusing to fulfill it.  An accompanying error message should explain why.
			 * 404 Not Found: either you're requesting an invalid URI or the resource in question doesn't exist (ex: no such user). 
			 * 500 Internal Server Error: we did something wrong.  Please post to the group about it and the Twitter team will investigate.
			 * 502 Bad Gateway: returned if Twitter is down or being upgraded.
			 * 503 Service Unavailable: the Twitter servers are up, but are overloaded with requests.  Try again later.
			 */

			String limit = "Rate limit exceeded";
			String unauthorized = "Login Unauthorized";
			String notFound = "User Not Found";
			String outOfService = "Out Of Service";
			String error = "Error";

			String message = "";

			int statusCode = e.getStatusCode();

			if (statusCode == 400) {
				message = limit;
			}
			else if (statusCode == 401) {
				message = unauthorized;				
			}
			else if (statusCode == 404) {
				message = notFound;				
			}
			else if (statusCode == -1) {
				message = outOfService;				
			}
			else {
				message = error;
			}
			frame.getStatusBar().setMessage(message + " (" + statusCode + ").");
		}
		finally {
			SuittarCommand.setCommandChanged(false);
			SuittarCommand.setExecFromTimer(false);
			timeLineRefreshCount = 0;			
			frame.getStatusBar().setRefreshing(false);
		}
	}

	public synchronized void updateStatus() {

		frame.getInputPane().setTextAreaEditable(false);
		String statusText = frame.getInputPane().getStatusPanel().getText();
		if (statusText != null && statusText.length() > 0) {
			try {

				frame.getStatusBar().setRefreshing(true);
				twitter.update(statusText);
				frame.getInputPane().getStatusPanel().clear();

				SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_FRIENDS);
				SuittarCommand.setScreenName(myUser.getScreenName());
				SuittarCommand.setPage(1);
				SuittarCommand.setExecFromTimer(false);
				
				setTimeLine();
			}
			catch(TwitterException e) {
				JOptionPane.showMessageDialog(frame,"Status has not changed.","Error",JOptionPane.ERROR_MESSAGE);
			}
			finally {
				frame.getStatusBar().setRefreshing(false);			
				frame.getInputPane().setTextAreaEditable(true);
			}
		}
	}

	public synchronized void sendDirectMessage() {

		String message = frame.getInputPane().getDirectMessagePanel().getText();
		String recipientId = frame.getInputPane().getDirectMessagePanel().getRecipientId();
		
		if (message != null && message.length() > 0) {
			try {

				frame.getStatusBar().setRefreshing(true);
				twitter.sendDirectMessage(recipientId, message);
				frame.getInputPane().getDirectMessagePanel().clear();
				
				SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_DIRECT_MESSAGE);
				SuittarCommand.setScreenName(myUser.getScreenName());
				SuittarCommand.setPage(1);

				setTimeLine();
			}
			catch(TwitterException e) {
				JOptionPane.showMessageDialog(frame,"Status has not changed.","Error",JOptionPane.ERROR_MESSAGE);
			}
			finally {
				frame.getStatusBar().setRefreshing(false);			
			}
		}
	}

	public void executeSuittarCommand() {
		
		Runnable refreshOneTime = null;
		
		switch (SuittarCommand.getCommand()) {
		
		case SuittarCommand.COMMAND_UPDATE_STATUS:
			if (frame.getInputPane().getStatusPanel().getText().length() == 0) {
				return;
			}
			refreshOneTime = new StatusUpdater();			
			break;
		case SuittarCommand.COMMAND_SEND_DIRECT_MESSAGE:
			if (frame.getInputPane().getDirectMessagePanel().getText().length() == 0) {
				return;
			}
			refreshOneTime = new DirectMessageSender();
			break;
		default:
			refreshOneTime = new TimeLineUpdater();			
		}
		
		showGrowl = false;
		future.cancel(true);
		future = exeService.schedule(refreshOneTime, 0, TimeUnit.MILLISECONDS);
		future = exeService.scheduleAtFixedRate(refreshThread, 0, 1000,TimeUnit.MILLISECONDS);
		
	}
	
	public void changeRefreshInterval() {

		int newInterval = frame.getStatusBar().getSelectedInterval();

		if (refreshInterval == newInterval) {
			return;
		}

		timeLineRefreshCount = 0;
		future.cancel(true);
		if (refreshInterval != 0 && newInterval == 0) {
			frame.getStatusBar().setProgressBarValue(0);
		}
		else {
			frame.getStatusBar().setProgressBarValue(0);
			frame.getStatusBar().setProgressBarMaximum(60 * newInterval);
		}
		future = exeService.scheduleAtFixedRate(refreshThread, 0, 1000,TimeUnit.MILLISECONDS);
		refreshInterval = newInterval;			
	}
	
	public void setAtMarkUser(String id) {
		frame.getInputPane().getStatusPanel().setAtMarkUser(id);
	}

	public void addFriend(String addId) {

		try {			
			User addUser = twitter.create(addId);
			myUser = twitter.getUserDetail(String.valueOf(myUser.getId()));
			getMyFollowingList();
			String msg = "Added " + addUser.getScreenName() + " to your friend list.";
			ImageIcon icon = new ImageIcon(addUser.getProfileImageURL());
			JOptionPane.showMessageDialog(frame, msg,"add friend",JOptionPane.INFORMATION_MESSAGE,icon);
			SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_PUBLIC);
			executeSuittarCommand();
		}
		catch (TwitterException e) {
			String[] errMsg = {"Exception occurred when add friend."};
			JOptionPane.showConfirmDialog(frame , errMsg ,"Error" , JOptionPane.OK_OPTION);
		}
	}

	public void removeFriend(String removeId) {

		try {
			User removeUser = twitter.destroy(removeId);
			myUser = twitter.getUserDetail(String.valueOf(myUser.getId()));
			getMyFollowingList();
			String msg = "Removed " + removeUser.getScreenName() + " from your friend list.";
			ImageIcon icon = new ImageIcon(removeUser.getProfileImageURL());
			JOptionPane.showMessageDialog(frame, msg,"add friend",JOptionPane.INFORMATION_MESSAGE,icon);
			SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_PUBLIC);
			executeSuittarCommand();
		}
		catch (TwitterException e) {
			String errMsg = "Exception occurred when remove friend.";
			JOptionPane.showMessageDialog(frame , errMsg ,"Error" , JOptionPane.ERROR_MESSAGE);
		}
	}

	public void executeBrowser(URL url) {
  	   boolean wasOpen = BrowserLauncher.openURL(url);
  	   if (!wasOpen) {
  		   JOptionPane.showConfirmDialog(frame, "ブラウザを起動できませんでした。","エラー",JOptionPane.OK_OPTION,JOptionPane.ERROR_MESSAGE);
  	   }
	}
		
	public void changeTab(boolean isMainTab) {
		
		if (tabChangeEventOff) {
			return;
		}
		
		showGrowl = false;
		
		int command = 0;
		
		//PUBLIC
		if (frame.getSelectedMainTabIndex() == SuittarFrame.TAB_MAIN_PUBLIC) {
			command = SuittarCommand.COMMAND_SHOW_PUBLIC;
		}
		//Owner
		else if (frame.getSelectedMainTabIndex() == SuittarFrame.TAB_MAIN_MYUSER) {
			
			if (isMainTab) {
				return;
			}
			
			SuittarCommand.setScreenName(myUser.getScreenName());
			
			switch (frame.getSelectedOwnerTabIndex()) {
			case SuittarTabbedPane.TAB_OWNER_FRIENDS:
				command = SuittarCommand.COMMAND_SHOW_FRIENDS;
				break;
			case SuittarTabbedPane.TAB_OWNER_PROFILE:
				command = SuittarCommand.COMMAND_SHOW_PROFILE;
				break;
			case SuittarTabbedPane.TAB_OWNER_REPLIES:
				command = SuittarCommand.COMMAND_SHOW_REPLIES;
				break;
			case SuittarTabbedPane.TAB_OWNER_FOLLOWING:
				command = SuittarCommand.COMMAND_SHOW_FOLLOWING;
				break;
			case SuittarTabbedPane.TAB_OWNER_FOLLOWERS:
				command = SuittarCommand.COMMAND_SHOW_FOLLOWERS;
				break;
			case SuittarTabbedPane.TAB_OWNER_DIRECT_MESSAGES:
				command = SuittarCommand.COMMAND_SHOW_DIRECT_MESSAGE;
				break;
			}			
		}
		//About
		else if (frame.getSelectedMainTabIndex() == SuittarFrame.TAB_MAIN_ABOUT) {
			frame.getMainPane(SuittarFrame.TAB_MAIN_ABOUT, SuittarFrame.TAB_MAIN_ABOUT).showAbout();
			return;			
		}
		//User
		else {
			if (isMainTab) {
				return;
			}
			UserWithStatus user = frame.getUserByTagIndex(frame.getSelectedMainTabIndex());
			SuittarCommand.setScreenName(user.getScreenName());
			switch (frame.getSelectedUserTabIndex(frame.getSelectedMainTabIndex())) {
			case SuittarTabbedPane.TAB_OTHER_FRIENDS:
				command = SuittarCommand.COMMAND_SHOW_FRIENDS;
				break;
			case SuittarTabbedPane.TAB_OTHER_PROFILE:
				command = SuittarCommand.COMMAND_SHOW_PROFILE;
				break;
			case SuittarTabbedPane.TAB_OTHER_FOLLOWING:
				command = SuittarCommand.COMMAND_SHOW_FOLLOWING;
				break;
			}			
			
		}
		if (command == SuittarCommand.COMMAND_SHOW_DIRECT_MESSAGE) {
			frame.getInputPane().setMode(SuittarInputPanel.MODE_DIRECT_MESSAGE);
		}
		else {
			frame.getInputPane().setMode(SuittarInputPanel.MODE_STATUS);
		}
		
		SuittarCommand.setCommand(command);
		executeSuittarCommand();
	}
	
	public void removeTabPane(int id) {
		frame.removeUserTab(id);
	}
	
	public static void main(String[] args) {
		//MacOSX 対応
		System.setProperty("apple.laf.useScreenMenuBar", "true");
		System.setProperty("com.apple.macos.smallTabs", "true");
		System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Suittar!");
		new Suittar();
	}

	class AutoTimeLineUpdater implements Runnable {

		public void run() {

			if (refreshInterval == 0) {
				return;
			}

			int interval = refreshInterval * 60;
			
	    	timeLineRefreshCount++;
			frame.getStatusBar().setProgressBarValue(Suittar.this.timeLineRefreshCount);
			if (timeLineRefreshCount >= interval) {
				if (frame.getSelectedMainTabIndex() == SuittarFrame.TAB_MAIN_PUBLIC) {
					SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_PUBLIC);					
				}
				else {
					switch (frame.getSelectedOwnerTabIndex()) {
					case SuittarTabbedPane.TAB_OWNER_FRIENDS:
						SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_FRIENDS);
						break;
					case SuittarTabbedPane.TAB_OWNER_PROFILE:
						SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_PROFILE);
						break;
					case SuittarTabbedPane.TAB_OWNER_REPLIES:
						SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_REPLIES);
						break;
					case SuittarTabbedPane.TAB_OWNER_FOLLOWING:
						SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_FOLLOWING);
						break;
					case SuittarTabbedPane.TAB_OWNER_FOLLOWERS:
						SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_FOLLOWERS);
						break;
					case SuittarTabbedPane.TAB_OWNER_DIRECT_MESSAGES:
						SuittarCommand.setCommand(SuittarCommand.COMMAND_SHOW_FRIENDS);
						break;
					}					
				}
				
				showGrowl = true;
				SuittarCommand.setScreenName(myUser.getScreenName());
				SuittarCommand.setPage(1);
				SuittarCommand.setExecFromTimer(true);
				setTimeLine();
			}
		}
			
	}

	class TimeLineUpdater implements Runnable {

		public void run() {
			setTimeLine();			
		}
	}
	
	class StatusUpdater implements Runnable {

		public void run() {
			updateStatus();
		}
	}
	
	class DirectMessageSender implements Runnable {

		public void run() {
			sendDirectMessage();
		}
	}
	
}

